using System;
using System.Diagnostics;
using OracleInternal.Network;

namespace OracleInternal.Common
{
	internal class ConOraBufPool
	{
		private OraBufPool m_obp;

		private static int m_sId = 0;

		private static object m_idSync = new object();

		internal int m_poolId;

		private OraBuf[] m_smallBufPooler;

		private OraBuf[] m_largeBufPooler;

		private object m_smallBufPoolerSync;

		private object m_largeBufPoolerSync;

		private int m_smallBufPoolerPos;

		private int m_largeBufPoolerPos;

		private int m_smallBufPoolerMin;

		private int m_smallBufPoolerMax;

		private int m_largeBufPoolerMin;

		private int m_largeBufPoolerMax;

		internal int m_smallBufSize;

		internal int m_largeBufSize;

		private int m_bufPoolerCapacity;

		public ConOraBufPool(OraBufPool obp)
		{
			lock (m_idSync)
			{
				m_poolId = ++m_sId;
			}
			m_obp = obp;
			m_bufPoolerCapacity = 127;
			m_smallBufPooler = new OraBuf[m_bufPoolerCapacity + 1];
			m_largeBufPooler = new OraBuf[m_bufPoolerCapacity + 1];
			m_smallBufPoolerSync = new object();
			m_largeBufPoolerSync = new object();
			m_smallBufPoolerPos = -1;
			m_largeBufPoolerPos = -1;
			m_smallBufPoolerMin = 8;
			m_largeBufPoolerMin = 0;
			m_smallBufPoolerMax = 16;
			m_largeBufPoolerMax = 4;
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				StackTrace stackTrace = new StackTrace();
				string name = stackTrace.GetFrame(1)!.GetMethod()!.Name;
				string name2 = stackTrace.GetFrame(1)!.GetMethod()!.ReflectedType!.Name;
				string text = $"(COBP.CTOR) (poolid:{m_poolId}) (parentpoolid:{m_obp.m_poolId}) ({name2}.{name})";
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BUF, OracleTraceClassName.ConOraBufPool, OracleTraceFuncName.ctor, text);
			}
		}

		public void Output(string method, int bufId, int key, int count)
		{
			StackTrace stackTrace = new StackTrace();
			string name = stackTrace.GetFrame(2)!.GetMethod()!.Name;
			string name2 = stackTrace.GetFrame(2)!.GetMethod()!.ReflectedType!.Name;
			string text = $"({method}) (poolid:{m_poolId}) (key:{key}) (bufid:{bufId}) (count:{count}) ({name2}.{name})";
			Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BUF, OracleTraceClassName.ConOraBufPool, OracleTraceFuncName.Output, text);
		}

		public OraBuf Get(int key, OracleCommunication oracleCommunication, bool bReceive)
		{
			OraBuf oraBuf = null;
			int count = 0;
			if (key == m_smallBufSize)
			{
				if (m_smallBufPoolerPos >= 0)
				{
					lock (m_smallBufPoolerSync)
					{
						if (m_smallBufPoolerPos >= 0)
						{
							oraBuf = m_smallBufPooler[m_smallBufPoolerPos];
							count = m_smallBufPoolerPos;
							m_smallBufPooler[m_smallBufPoolerPos--] = null;
						}
					}
				}
			}
			else if (key == m_largeBufSize && m_largeBufPoolerPos >= 0)
			{
				lock (m_largeBufPoolerSync)
				{
					if (m_largeBufPoolerPos >= 0)
					{
						oraBuf = m_largeBufPooler[m_largeBufPoolerPos];
						count = m_largeBufPoolerPos;
						m_largeBufPooler[m_largeBufPoolerPos--] = null;
					}
				}
			}
			if (oraBuf == null)
			{
				oraBuf = ((m_obp != null) ? m_obp.Get(key, oracleCommunication, bReceive) : new OraBuf(oracleCommunication, key, bReceive));
			}
			else
			{
				oraBuf.ReInit(bReceive);
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Output("COBP.GET", oraBuf.m_id, key, count);
			}
			return oraBuf;
		}

		public void Put(int key, OraBuf oraBuf)
		{
			int count = 0;
			if (oraBuf.m_size == m_smallBufSize)
			{
				if (m_smallBufPoolerPos < m_bufPoolerCapacity)
				{
					lock (m_smallBufPoolerSync)
					{
						if (m_smallBufPoolerPos < m_bufPoolerCapacity)
						{
							m_smallBufPooler[++m_smallBufPoolerPos] = oraBuf;
							count = m_smallBufPoolerPos + 1;
						}
					}
				}
			}
			else if (oraBuf.m_size == m_largeBufSize && m_largeBufPoolerPos < m_bufPoolerCapacity)
			{
				lock (m_largeBufPoolerSync)
				{
					if (m_largeBufPoolerPos < m_bufPoolerCapacity)
					{
						m_largeBufPooler[++m_largeBufPoolerPos] = oraBuf;
						count = m_largeBufPoolerPos + 1;
					}
				}
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Output("COBP.PUT", oraBuf.m_id, oraBuf.m_size, count);
			}
		}

		public void Init(OracleCommunication oc)
		{
			OraBuf oraBuf = null;
			int count = 0;
			int bufId = 0;
			for (int i = 0; i < 2; i++)
			{
				OraBuf[] array;
				object obj;
				int num;
				int num2;
				int num3;
				int num4;
				if (i == 0)
				{
					array = m_smallBufPooler;
					obj = m_smallBufPoolerSync;
					num = m_smallBufPoolerPos + 1;
					num2 = m_smallBufPoolerMin;
					num3 = m_smallBufPoolerMax;
					if (m_smallBufSize == 0)
					{
						m_smallBufSize = oc.m_sessionCtx.m_sessionDataUnit;
					}
					num4 = m_smallBufSize;
				}
				else
				{
					array = m_largeBufPooler;
					obj = m_largeBufPoolerSync;
					num = m_largeBufPoolerPos + 1;
					num2 = m_largeBufPoolerMin;
					num3 = m_largeBufPoolerMax;
					if (m_largeBufSize == 0)
					{
						m_largeBufSize = oc.m_sessionCtx.m_sessionDataUnit * 4;
					}
					num4 = m_largeBufSize;
				}
				if (num < num2)
				{
					int num5 = num2 - num;
					for (int j = 0; j < num5; j++)
					{
						if (m_obp != null)
						{
							lock (obj)
							{
								oraBuf = m_obp.GetUninitialized(num4, oc);
								if (i == 0)
								{
									array[++m_smallBufPoolerPos] = oraBuf;
									count = m_smallBufPoolerPos + 1;
								}
								else
								{
									array[++m_largeBufPoolerPos] = oraBuf;
									count = m_largeBufPoolerPos + 1;
								}
								bufId = oraBuf.m_id;
							}
						}
						else
						{
							lock (obj)
							{
								oraBuf = new OraBuf(oc, num4);
								if (i == 0)
								{
									array[++m_smallBufPoolerPos] = oraBuf;
									count = m_smallBufPoolerPos + 1;
								}
								else
								{
									array[++m_largeBufPoolerPos] = oraBuf;
									count = m_largeBufPoolerPos + 1;
								}
								bufId = oraBuf.m_id;
							}
						}
						if (ProviderConfig.m_bTraceLevelPrivate)
						{
							Output("COBP.PUT", bufId, num4, count);
						}
					}
				}
				else
				{
					if (num <= num3)
					{
						continue;
					}
					int num6 = num - num3;
					for (int k = 0; k < num6; k++)
					{
						int num7 = 0;
						num7 = ((i != 0) ? m_largeBufPoolerPos : m_smallBufPoolerPos);
						if (num7 >= 0)
						{
							lock (obj)
							{
								num7 = ((i != 0) ? m_largeBufPoolerPos : m_smallBufPoolerPos);
								if (num7 >= 0)
								{
									if (i == 0)
									{
										oraBuf = array[m_smallBufPoolerPos];
										count = m_smallBufPoolerPos;
										array[m_smallBufPoolerPos--] = null;
									}
									else
									{
										oraBuf = array[m_largeBufPoolerPos];
										count = m_largeBufPoolerPos;
										array[m_largeBufPoolerPos--] = null;
									}
									bufId = oraBuf.m_id;
								}
							}
						}
						if (ProviderConfig.m_bTraceLevelPrivate)
						{
							Output("COBP.GET", bufId, num4, count);
						}
						if (m_obp != null)
						{
							m_obp.Put(num4, oraBuf);
						}
					}
				}
			}
		}

		public void ReturnAll()
		{
			int count = 0;
			int bufId = 0;
			GC.SuppressFinalize(this);
			if (m_smallBufPoolerPos >= 0)
			{
				lock (m_smallBufPoolerSync)
				{
					if (m_smallBufPoolerPos >= 0)
					{
						while (m_smallBufPoolerPos >= 0)
						{
							OraBuf oraBuf = m_smallBufPooler[m_smallBufPoolerPos];
							if (ProviderConfig.m_bTraceLevelPrivate)
							{
								Output("COBP.RETURNALL", bufId, m_smallBufSize, count);
							}
							m_obp.Put(m_smallBufSize, oraBuf);
							count = m_smallBufPoolerPos;
							m_smallBufPooler[m_smallBufPoolerPos] = null;
							bufId = oraBuf.m_id;
							m_smallBufPoolerPos--;
						}
					}
				}
			}
			if (m_largeBufPoolerPos < 0)
			{
				return;
			}
			lock (m_largeBufPoolerSync)
			{
				if (m_largeBufPoolerPos < 0)
				{
					return;
				}
				while (m_largeBufPoolerPos >= 0)
				{
					OraBuf oraBuf2 = m_largeBufPooler[m_largeBufPoolerPos];
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Output("COBP.RETURNALL", bufId, m_largeBufSize, count);
					}
					m_obp.Put(m_largeBufSize, oraBuf2);
					count = m_largeBufPoolerPos;
					m_largeBufPooler[m_largeBufPoolerPos] = null;
					bufId = oraBuf2.m_id;
					m_largeBufPoolerPos--;
				}
			}
		}
	}
}
